package com.itany.shop.util;

import com.itany.shop.exception.DataAccessException;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @Author:石小俊
 * JDBC工具类
 * 使用这个类需要读取类加载路径中的文件:dataSource.properties
 * 在该文件中对数据源进行配置,配置数据库连接的相关信息
 * 此处使用commons-dbcp进行配置
 */
public class JDBCUtil {

    private static DataSource ds;
    private static ThreadLocal<Connection> local;

    static{
        local = new ThreadLocal<>();
        Properties p = new Properties();
        try {
            p.load(JDBCUtil.class.getClassLoader().getResourceAsStream("dataSource.properties"));
            // 德鲁伊
            // ds = DruidDataSourceFactory.createDataSource(p);
            // dbcp
            ds = BasicDataSourceFactory.createDataSource(p);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("JDBCUtil初始化失败");
        }
    }

    /**
     * 使用common-dbcp连接池获取一个Connection对象,该对象线程单例
     * @return  跟本线程相关的Connection对象
     */
    public static Connection getConnection(){
        // 从线程池中获取Connection对象
        Connection conn = local.get();
        try {
            // 当没有取到Connection对象,说明尚未存放
            if(null == conn){
                // 从连接池中取出一个连接
                conn = ds.getConnection();
                // 当拿到连接之后,将连接放入到线程池中
                // 便于下次使用时直接从线程池中取出
                local.set(conn);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DataAccessException("获取连接失败");
        }
        return conn;
    }

    /**
     * 释放指定资源
     * 一般用于持久化操作之后,业务可能尚未结束
     * @param conn  连接
     * @param ps    状态集
     * @param rs    结果集
     */
    public static void close(Connection conn, PreparedStatement ps, ResultSet rs){
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                throw new DataAccessException("释放连接失败");
            }
        }
        if(ps != null){
            try {
                ps.close();
            } catch (SQLException e) {
                throw new DataAccessException("释放状态集失败");
            }
        }
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                throw new DataAccessException("释放结果集失败");
            }
        }
    }

    /**
     * 释放当前线程相关的连接
     * 一般用于当前业务结束之后释放
     */
    public static void close(){
        // 从线程池中取出对应连接对象
        Connection conn = local.get();
        // 如果取到了对应的连接,说明尚未从线程池中释放
        if(conn != null){
            try {
                conn.close();
                // 将对应的连接从线程池中移除
                local.remove();
            } catch (SQLException e) {
                throw new DataAccessException("释放连接失败");
            }
        }
    }
}
